I - Structure de l'Import Address Table
II - Ajoutez vos propres DLL ou Fonctions manuellement.
III - Les IAT hors normes.
IV - Les différents liens.
V - Programme d'automatisation.
Cette table ne fait pas partie du PE Header. C'est une section à part
entière souvent appelée .idata ou parfois .rdata. On peut même
trouver les deux ensembles, mais je ne pourrais pas vous dire pourquoi, je ne
suis pas allé aussi loin dans mes recherches.
Le rôle de cette section est vital. Pour faire simple, elle contient les
noms des DLLs et de chacune de leurs fonctions utilisées par votre programme.
En pratique si votre programme utilise seulement ExitProcess (de Kernel32.dll)
et MessageBoxA (User32.dll), ils sont tous inscrits dans cette section et vous
ne pouvez utiliser aucune des autres fonctions de Kernel ou User32 parce que
même si elles existent (et elles existent), elles ne sont pas notifiées
dans ce carnet de bord. Vous pouvez encore moins utiliser des fonctions provenant
d'autres DLLs.
Sachez une dernière chose, les fonctions importées, sont retrouvées
soit d'après leur nom soit d'après un numéro. Celui-ci
est appelé l'ORDINAL de la fonction.
Quel est l'intérêt ?
....... Il existe autant de structures IMAGE_IMPORT_DESCRIPTOR qu'il y a de DLL appellées par votre programme .... + un dernier IMAGE_IMPORT_DESCRIPTOR remplit de 5 DWORD NULL en tant que terminaison ..
........
... ... Il y a autant de fois de Structures IMAGE_IMPORT_BY_NAME qu'il y a de Fonctions dans la DLL considérée. ... Donc ici on considère que notre programme n'importe que 3 fonctions appartenant à la DLL1 par exemple. ... |
DISSECTION :
Dans la section .idata toutes les références pour aller
d'une adresse à une autre sont définit par rapport au tout début
du programme (MZ). C'est pour ça qu'elle n'utilise que des RVA pour décrire
l'emplacement d'une autre adresse. Pour éclaircir ce point, un RVA c'est
pas une adresse, c'est un déplacement par rapport à un point fixe.
Un RVA c'est une distance tout simplement.
IMAGE_IMPORT_DESCRIPTOR:
Chaque structure IMAGE_IMPORT_DESCRIPTOR est destinée à une DLL.
Et elle contient toujours 5 membres de taille DWORD. Le premier et dernier membre
(Original First Thunk
et First Thunk) pointent sur deux autres
structures qui normalement sont identiques. Dans l'exemple ci-dessus je n'ai
représenté qu'une seule fois ce tableau mais il y a son double
qui le suit normalement et chacun des deux (Original First Thunk et First Thunk)
pointe sur un tableau (jumeau)
Date Time Stamp,
normalement, il est mis à 00000000h, sauf dans le cas où le programme
présente une section "Delay Import Descriptor". Dans ce cas
seulement ce dword représente la date complète de création
de la DLL. Pour ce que j'en ai compris, "Delay Import Descriptor"
serait un équivalent de l'IAT mis à par qu'on y trouverait les
véritables adresses des fonctions de la DLL. Et c'est pour ça
que sa date de conception devient importante, c'est pour trier les différentes
versions d'une même DLL. (Vous remarquerez que "Delay Import Descriptor"
n'est pas accessible dans ProcDump, et y en a un autre aussi)
Forwarder Chain est un dword réservé
et d'après la doc officielle il doit être mis à FFFFFFFFh
cependant, je l'ai déjà rencontré à 00000000h lui
aussi.
Name est l'adresse (On parle toujours en
adresse relative et c'est vrai pour tout le tut:RVA) où commence la chaîne
de caractères représentant le nom de la DLL en question. Cette
chaîne sera toujours suivit d'un byte 00h de terminaison. Dans l'exemple,
je n'ai pas représenté ou était sa position, cette adresse
se trouve à la suite de tous les tableaux, à la fin de la section
.idata. Et d'ailleurs cette fin de tableau contient les noms de DLL+00 puis
les noms DES Fonctions+00 et on recommence pour la DLL suivante. Cependant,
on peut très bien prendre un ordre complètement différent.
IMAGE_THUNK_DATA :
Grâce à ce qui précède, on connait les noms des
DLLs utilisées par notre programme. Reste à connaître chacune
des fonctions de chaque DLL. C'est le rôle de IMAGE_THUNK_DATA. Chaque
DWORD qu'elle contient représente
l'adresse où on va retrouver le n°ORDINAL de la fonction + son nom
qui le suit tout de suite après.
Un DWORD pointe donc sur : n°ORDINAL(de longueur 1 WORD)+Chaine de caractère(nom
d'une fonction)+00h pour la terminaison.
Mais il y a un cas particulier. Ce DWORD n'est pas toujours une adresse vers
ces deux données. Si le MSB (le byte de poids fort du DWORD est à
1) alors ça signifie qu'il ne faut pas le considérer comme un
RVA. Et dans ce cas seuleument l'autre partie de ce DWORD (le WORD Bas) est
le n°ORDINAL de la fonction. Dans cette configuration particulière
on n'a pas de nom pour notre fonction. On sait seulement que notre programme
l'utilise en se référent à son n°. (Il est possible
de retrouver son nom mais alors il faut aller le chercher dans la table d'exportation
de la DLL avec le même n° trouvé).
IMAGE_IMPORT_BY_NAME :
Il en existe autant qu'il y a de fonctions, forcément (excepté
dans le cas des ordinaux), puisqu'elles contiennent le n° et noms de ces
fonctions. La taille de cette structure est non définit puisqu'elle dépend
toujours de la longeur des noms qu'elle contient.
Cependant vous trouverez une taille de 3 Bytes si vous lui faites subir un SIZEOF.....
Car elle est ainsi définit dans la bibliothèque Windows.inc
IMAGE_IMPORT_BY_NAME STRUCT
Hint dw ? ;
<------------------------------n°ORDINAL
Name1 db ? ;
<------------------------------Nom de la fonction
IMAGE_IMPORT_BY_NAME ENDS
Mais comprenez que vous ne pouvez et ne devez sûrtout pas accepter cette
valeur comme étant viable.